package com.sduept.nwld.dataserver.manager.etl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.apache.commons.lang3.StringUtils;

import com.sduept.bigdata.fault.entity.FaultRecord;
import com.sduept.bigdata.fault.entity.FaultRecordWrapper;
import com.sduept.bigdata.fault.entity.FaultReportComponentDetail;
import com.sduept.bigdata.fault.entity.FaultReportMain;
import com.sduept.bigdata.fault.entity.FaultReportStationDetail;
import com.sduept.bigdata.fault.enums.RegexTypeEnum;
import com.sduept.bigdata.fault.manager.FaultReportPersistManager;
import com.sduept.bigdata.fault.parser.entity.StandardLibrary;
import com.sduept.cim.ledger.manager.SubstationLedgerManager;
import com.sduept.cim.ledger.model.SubstationLedger;
import com.sduept.cim.model.extend.LineSegment;
import com.sduept.cim.model.wires.DcLinesegment;
import com.sduept.generator.ObjectId;
import com.sduept.nwld.dataserver.model.daily.Runlog;
import com.sduept.nwld.dataserver.util.CimUtils;

/**
 * 直流线路故障抽取
 * @author Author
 *
 */
@Service
public class DcLineFaultDataETLManager extends FaultETLDataManager  {

	@Autowired
	private FaultReportPersistManager reportManager;
	@Autowired
	private SubstationLedgerManager stationLedgerM;

	private static final String SIGN_DC_SUCCESS = ".*成功.*";
	private static final String SIGN_DC_FAILED = ".*(不成功|失败).*";
	private static final String SIGN_DC_FAULT_TYPE_SINGLE_INSTANT = "瞬时性";
	private static final String SIGN_DC_FAULT_TYPE_SINGLE_PERMANT = "永久性";
	private static final String SIGN_PROTECT_FIRST = "主一保护";
	private static final String SIGN_PROTECT_SECOND = "主二保护";
	private static final String SIGN_PROTECT_THIRD = "主三保护";
	private static final String SIGN_ONE_REGE = ".*第一套.*";
	private static final String SIGN_TWO_REGE = ".*第二套.*";
	private static final String SIGN_THREE_REGE = ".*第三套.*";

	/**
	 * 直流线路故障记录抽取
	 */
	public void extracFaultRecord(Runlog record, Map<String, List<StandardLibrary>> map) throws Exception {
		if (StringUtils.isEmpty(record.getLog_contents())) {
			return;
		}
		List<StandardLibrary> list = map.get(RegexTypeEnum.DCLINE_FAULT_REGEX.getCode());
		boolean matcher = FaultRegexUtil.isMatcher(record.getLog_contents(), list);
		if (!matcher) {
			return;
		}
		List<StandardLibrary> dataList = map.get(RegexTypeEnum.DCLINE_DATA_REGEX.getCode());
		List<StandardLibrary> list2 = map.get(RegexTypeEnum.DCLINESEGEMNET_FAULT_CONDITION_REGEX.getCode());
		List<StandardLibrary> list3 = map.get(RegexTypeEnum.DCLINE_LINE_REGEX_SPARE.getCode());
		List<StandardLibrary> timeList = map.get(RegexTypeEnum.SIGN_FAULT_TIME_REGEX.getCode());
		String[] strings = record.getLog_contents().split(DEFAULT_SPLIT_REGEX);
		for (String faultDesc : strings) {
			boolean singleMatcher = FaultRegexUtil.isMatcher(faultDesc, list);
			if (!singleMatcher) {
				continue;
			}
			FaultRecord fault = new FaultRecord();
			fault.setSource(4);
			Date faultTime = getFaultTime(faultDesc, record.getTime(), timeList);
			if (null == faultTime) {
				continue;
			}
			fault.setId(ObjectId.get().toString());
			fault.setFaultTime(faultTime);
			String v = find1("([0-9]+)kV", faultDesc);
			fault.setVoltage(v.equals("") ? null : Integer.parseInt(v));
			fault.setFaultPhase(getDclineFaultPhase(faultDesc));
			fault.setFaultType(getDclineFaultType(faultDesc));
			fault.setEtype("线路");
			String equipment = null;
			// 为了去除后面带极一的情况。eg:动作前后极二
			String temp = getFirstMatcher(faultDesc, list2);
			if (StringUtils.isEmpty(temp)) {
				equipment = getFirstMatcher(faultDesc, dataList);
			} else {
				equipment = getFirstMatcher(temp, dataList);
			}
			// 为了去除如下情况：18:51 金官换流站金中直流A、B套极二直流过压开路保护
			if (StringUtils.isEmpty(equipment) && StringUtils.isNotEmpty(temp)) {
				if (temp.contains("站")) {
					temp = temp.substring(temp.indexOf("站") + 1, temp.length());
				}
				equipment = getFirstMatcher(temp, list3);
			}
			if (StringUtils.isEmpty(equipment)) {
				continue;
			}
			String type = getLineType(equipment);
			if(SIGN_AC_LINE.equals(type)){
				continue;
			}
			DcLinesegment dcline = queryDcLinesegment(equipment);
			fault.setEquipment(equipment);
			if (dcline != null) {
				// 直流线路需要用到别称
				fault.setEquipment(dcline.getAliasName());
				fault.setEquipment_id(dcline.getId());
				fault.setStationId(dcline.getStartST());
				fault.setStationId2(dcline.getEndST());
				fault.setStationName(dcline.getStartStName());
				fault.setStationName2(dcline.getEndStName());
				if (null == fault.getVoltage()) {
					fault.setVoltage((int) dcline.getStandVoltagelevel());
				}
			}
			if (fault.getVoltage() == null || fault.getVoltage() < 500) {
				continue;
			}
			if (StringUtils.isEmpty(fault.getRank()) && StringUtils.isNotEmpty(fault.getStationId())) {
				SubstationLedger stationLedger = stationLedgerM.findSubstationLedger(fault.getStationId());
				if(null != stationLedger) {
					fault.setRank(stationLedger.getPrimaryEquipmentScope());
				}
			}
			fm.saveFaultRecord(new FaultRecordWrapper(fault));
		}

	}

	/**
	 * 故障的巡线结果抽取，包括 ：故障原因、故障杆塔以及巡线结果
	 */
	public void extracFaultResult(Runlog record, Map<String, List<StandardLibrary>> map) throws Exception {
		List<StandardLibrary> list = map.get(RegexTypeEnum.RESULT_DATA_REGEX.getCode());
		if (!FaultRegexUtil.isMatcher(record.getLog_contents(), list)) {
			return;
		}
		String[] strings = record.getLog_contents().split("。");
		for (String s : strings) {
			if (s.contains(SIGN_RESULT_FAULT)) {
				updateByInspectionResults(s, record.getTime(), map);
			}
		}
	}

	/**
	 * 故障过程抽取，包括：行波测距，并更新到故障报告中去
	 */
	public void extracFaultProcess(Runlog record, Map<String, List<StandardLibrary>> map) throws Exception {
		if (StringUtils.isEmpty(record.getLog_contents())) {
			return;
		}
		String signAction = map.get(RegexTypeEnum.ACTION_PROTECT_CONDITION_REGEX.getCode()).get(0).getName();
		if (StringUtils.isEmpty(signAction)) {
			signAction = SIGN_PROTECT_ACTION_CONDITION;
		}
		if (!record.getLog_contents().contains(signAction)) {
			return;
		}
		// 更新两相接地两相相间故障原因与故障描述
		String sign = record.getLog_contents().substring(0, record.getLog_contents().indexOf(signAction));
		sign = sign.replaceAll(SIGN_VOLTAGE_REGEX, "");
		if (!sign.contains("报")) {
			return;
		}
		String[] split = sign.split("报");
		if (split.length != 2) {
			return;
		}
		String subName = split[0];
		if (StringUtils.isEmpty(subName)) {
			return;
		}
		String devName = split[1];
		if(StringUtils.isEmpty(devName)){
			return ;
		}
		String lineType = getLineType(devName);
		if(!lineType.equals(SIGN_DC_LINE)){
			return ;
		}
		LineSegment lineSegment = getLineSegmentByName(devName, map);
		List<FaultRecord> condition = null;
		if (null == lineSegment) {
			condition=getRecords(null, devName, record);
		} else {
			condition=getRecords(lineSegment.getId(), null, record);
		}
		if (condition.size() == 0) {
			return;
		}
		for (FaultRecord faRecord : condition) {
			// 更新动作元件
			try {
				generateDclineActionCompents(subName, record.getLog_contents(), faRecord, map);
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (StringUtils.isEmpty(faRecord.getRanging()) || !isContainStation(faRecord.getRanging(), subName)) {
				// 更新故障类型
				if (StringUtils.isEmpty(faRecord.getFaultType()) && StringUtils.isNotEmpty(faRecord.getFaultPhase())) {
					String faultType = getFaultType(record.getLog_contents(), faRecord.getFaultPhase());
					faRecord.setFaultType(faultType);
				}
				// 更新测距信息
				String[] rtn = getRanging(subName, record.getLog_contents(), map);
				if (null == rtn) {
					continue;
				}
				if (StringUtils.isEmpty(faRecord.getRanging()) && StringUtils.isNotEmpty(rtn[1])) {
					faRecord.setRanging(rtn[1]);
				} else if (StringUtils.isNotEmpty(rtn[1])) {
					faRecord.setRanging(faRecord.getRanging() + rtn[1]);
				}
				if (StringUtils.isEmpty(rtn[0])) {
					continue;
				}
				try {
					// 更新故障报告中测距
					updateFaultReportByFaultRecord(faRecord, rtn[0]);
					// 更新杆塔
					updateST(faRecord, map);
				} catch (Exception e) {
					e.printStackTrace();
				}
				// 如果杆塔为空，使用测距计算出的杆塔号
				if (faRecord.getStartPole() == null) {
					try {
						fm.setupFaultTower(faRecord);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
			dao.createOrUpdate(faRecord, FaultRecord.class);
		}
	}

	public String[] getRanging(String subName, String desc, Map<String, List<StandardLibrary>> map) {
		String[] rtns = new String[2];
		String s = subName + "：";
		String temp = subName + "：";
		String rtn = desc.substring(desc.indexOf(SIGN_PROTECT_ACTION_CONDITION), desc.length());
		String spiltSign="";
		List<StandardLibrary> splitList = map.get(RegexTypeEnum.SIGN_PROTECT_RANGING_REGEX.getCode());
		if(null==splitList||splitList.size()==0){
			spiltSign=SIGN_PROTECT_RANGING_REGEX;
		}else{
			spiltSign=splitList.get(0).getName();
		}
		String[] strings = null;
		if (rtn.contains(spiltSign)) {
			strings = rtn.split(spiltSign);
		} else {
			strings = rtn.split("km");
		}
		if (null == strings) {
			return rtns;
		}
		List<StandardLibrary> oneList = map.get(RegexTypeEnum.LINE_PROTECT_ONE_REGEX.getCode());
		List<StandardLibrary> twoList = map.get(RegexTypeEnum.LINE_PROTECT_TWO_REGEX.getCode());
		List<StandardLibrary> threeList = map.get(RegexTypeEnum.LINE_PROTECT_THREE_REGEX.getCode());
		for (String str : strings) {
			str=str.replaceAll("\n", "").replace("\r", "");
			if (FaultRegexUtil.isMatcher(str, oneList) && !s.matches(SIGN_ONE_REGE)) {
				String dis = DealWithWaveRanG(str);
				if (StringUtils.isNotEmpty(dis)) {
					s = s + SIGN_PROTECT_ONE + dis + "km，";
				}
			} else if (FaultRegexUtil.isMatcher(str, twoList) && !s.matches(SIGN_TWO_REGE)) {
				String dis = DealWithWaveRanG(str);
				if (StringUtils.isNotEmpty(dis)) {
					s = s + SIGN_PROTECT_TWO + dis + "km，";
				}
			} else if (FaultRegexUtil.isMatcher(str, threeList) && !s.matches(SIGN_THREE_REGE)) {
				String dis = DealWithWaveRanG(str);
				if (StringUtils.isNotEmpty(dis)) {
					s = s + SIGN_PROTECT_THREE + dis + "km，";
				}
			}
		}
		// 增加对以下情况的数据抽取
		// eg:广州换流站侧无保护动作，仅行波测距装置有测距结果，分别为：山东科汇装置测距结果为879.564km；电科院装置测距结果为878.028km、878.665km。
		if (temp.equals(s)) {
			List<StandardLibrary> list = map.get(RegexTypeEnum.SIGN_DC_DISTANCE_REGEX.getCode());
			if (list == null || list.size() == 0) {
				return rtns;
			}
			List<String> matchers = getMatchers(list.get(0).getName(), desc);
			for (String m : matchers) {
				if (matchers.indexOf(m) == 0) {
					s = s + SIGN_PROTECT_ONE + m + "，";
				} else if (matchers.indexOf(m) == 1) {
					s = s + SIGN_PROTECT_TWO + m + "，";
				} else if (matchers.indexOf(m) == 2) {
					s = s + SIGN_PROTECT_THREE + m + "，";
				}
			}
		}
		if (!s.endsWith("；")) {
			if (s.endsWith("，")) {
				s = s.substring(0, s.lastIndexOf("，"));
				s = s + "；";
			} else if (s.endsWith("：")) {
				s = null;
			}

		}
		rtns[0] = s;
		rtns[1] = s;
		return rtns;
	}

	/**
	 * 根据调度日志信息查询出直流线路的故障。目前直流线路故障分为：极一 /极二
	 * 
	 * @param desc
	 * @return
	 */
	private String getDclineFaultPhase(String desc) {
		if (desc.contains(SIGN_DC_PHASE_ONE)) {
			return SIGN_DC_PHASE_ONE;
		} else if (desc.contains(SIGN_DC_PHASE_TWO)) {
			return SIGN_DC_PHASE_TWO;
		}
		return null;
	}

	/**
	 * 获取直流线路故障的类型：瞬时性、永久性
	 * 
	 * @param desc
	 * @return
	 */
	private String getDclineFaultType(String desc) {
		if (desc.matches(SIGN_DC_FAILED)) {
			return SIGN_DC_FAULT_TYPE_SINGLE_PERMANT;
		} else if (desc.matches(SIGN_DC_SUCCESS)) {
			return SIGN_DC_FAULT_TYPE_SINGLE_INSTANT;
		}
		return null;
	}

	/**
	 * 获取直流线路故障的动作元件 2018-05-30
	 * 
	 * @param subName
	 * @param str
	 * @param record
	 */
	private void generateDclineActionCompents(String subName, String str, FaultRecord record, Map<String, List<StandardLibrary>> map) {
		if (!SIGN_LINE.equals(record.getEtype())) {
			return;
		}
		if (str == null) {
			return;
		}
		List<FaultReportMain> rtn = dao.findByCondition(FaultReportMain.class, "faultRecord.id=?", record.getId());
		if (rtn.size() == 0) {
			return;
		}
		FaultReportMain reportMain = rtn.get(0);
		Set<FaultReportStationDetail> faultReportStationDetails = reportMain.getFaultReportStationDetails();
		String[] stationData = str.split("：");
		if (stationData == null || stationData.length != 2) {
			return;
		}
		for (FaultReportStationDetail stationDetail : faultReportStationDetails) {
			if (!CimUtils.stationNameMatching(subName, stationDetail.getStationName(), true)) {
				continue;
			}
			List<FaultReportComponentDetail> result = genereateComponentList(stationData[1], map);
			reportManager.saveFaultReportActionComponet(record.getId(), stationDetail.getStationId(), result);
		}
	}

	private List<FaultReportComponentDetail> genereateComponentList(String str, Map<String, List<StandardLibrary>> map) {
		List<FaultReportComponentDetail> result = new ArrayList<>();
		if (StringUtils.isEmpty(str)) {
			return result;
		}
		String[] temp = null;
		if (str.contains(SIGN_PROTECT_RANGING_REGEX)) {
			temp = str.split(SIGN_PROTECT_RANGING_REGEX);
		} else {
			temp = str.split("km");
		}
		if (null == temp) {
			return result;
		}
		List<StandardLibrary> oneList = map.get(RegexTypeEnum.LINE_PROTECT_ONE_REGEX.getCode());
		List<StandardLibrary> twoList = map.get(RegexTypeEnum.LINE_PROTECT_TWO_REGEX.getCode());
		List<StandardLibrary> threeList = map.get(RegexTypeEnum.LINE_PROTECT_THREE_REGEX.getCode());
		for (String s : temp) {
			if (FaultRegexUtil.isMatcher(s, oneList)) {
				List<FaultReportComponentDetail> list = genereateComponentListByProtectName(s, SIGN_PROTECT_FIRST,map);
				result.addAll(list);
			} else if (FaultRegexUtil.isMatcher(s, twoList)) {
				List<FaultReportComponentDetail> list = genereateComponentListByProtectName(s, SIGN_PROTECT_SECOND,map);
				result.addAll(list);
			} else if (FaultRegexUtil.isMatcher(s, threeList)) {
				List<FaultReportComponentDetail> list = genereateComponentListByProtectName(s, SIGN_PROTECT_THIRD,map);
				result.addAll(list);
			}
		}
		return result;

	}

	private LineSegment getLineSegmentByName(String name, Map<String, List<StandardLibrary>> map) {
		LineSegment rtn = null;
		List<StandardLibrary> list = map.get(RegexTypeEnum.DCLINE_DATA_REGEX.getCode());
		String lineName = getFirstMatcher(name, list);
		if (StringUtils.isNotEmpty(lineName)) {
			rtn = queryDcLinesegment(lineName);
		}
		return rtn;
	}

	/**
	 * 根据保护名称 生成动作元件列表
	 * 
	 * @param str
	 * @param protectName
	 * @return
	 */
	private List<FaultReportComponentDetail> genereateComponentListByProtectName(String str, String protectName,Map<String, List<StandardLibrary>> regexMap) {
		List<FaultReportComponentDetail> result = new ArrayList<>();
		Map<String, String> map = getDCLineCompentsMap(regexMap);
		for (Map.Entry<String, String> entry : map.entrySet()) {
			if (str.contains(entry.getKey())) {
				FaultReportComponentDetail detail = new FaultReportComponentDetail();
				detail.setProtectName(protectName);
				detail.setActionComponent(entry.getValue());
				detail.setProtectType("线路保护");
				result.add(detail);
			}
		}

		return result;
	}

	/**
	 * 直流线路保护动作元件Map
	 * 
	 * @return
	 */
	private Map<String, String> getDCLineCompentsMap(Map<String, List<StandardLibrary>> regexMap) {
		HashMap<String, String> results = new HashMap<>();
//		results.put("行波保护", "行波保护（WFPDL）");
//		results.put("电压突变量保护", "电压突变量保护（27du/dt）");
//		results.put("电压突量保护", "电压突变量保护（27du/dt）");
//		results.put("低电压保护", "低电压保护（27DCOP）");
//		results.put("纵差保护", "纵差保护（87DCLL）");
//		results.put("横差保护", "横差保护（87DCLT）");
		List<StandardLibrary> list = regexMap.get(RegexTypeEnum.DCLINE_ACTION_INFO_ACCURATE.getCode());
		for(StandardLibrary temp:list){
			if(StringUtils.isEmpty(temp.getName())||StringUtils.isEmpty(temp.getDescription())){
				continue;
			}
			results.put(temp.getName(), temp.getDescription());
		}
		return results;
	}

}
